#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
BIN文件加载器和升级流程处理模块

该模块提供以下功能:
1. 解析和加载二进制格式文件
2. 将BIN数据加载到内存中
3. 提供简单的API接口用于访问BIN数据
4. 实现基本的固件升级流程
"""

import os
from typing import Dict, List, Tuple, Optional


class BinLoader:
    """BIN文件加载器类"""
    
    def __init__(self):
        """初始化BIN加载器"""
        self.bin_data = None      # 原始BIN文件内容 (bytes)
        self.memory_data = None   # 内存中的数据 (bytes)
        self.file_path = None     # 文件路径
        self.file_size = 0        # 文件大小
        self.load_address = 0     # 加载地址
        
    def load_bin_file(self, file_path: str, load_address: int = 0) -> bool:
        """
        加载BIN文件到内存
        
        Args:
            file_path (str): BIN文件路径
            load_address (int): 加载到内存的起始地址，默认为0
            
        Returns:
            bool: 加载成功返回True，否则返回False
        """
        try:
            if not os.path.exists(file_path):
                raise FileNotFoundError(f"文件不存在: {file_path}")
            
            self.file_path = file_path
            self.file_size = os.path.getsize(file_path)
            self.load_address = load_address
            
            # 以二进制模式读取文件
            with open(file_path, 'rb') as file:
                self.bin_data = file.read()
            
            # 将数据存储为内存数据
            self.memory_data = self.bin_data
            
            return True
            
        except Exception as e:
            print(f"加载BIN文件失败: {str(e)}")
            return False
    
    def get_memory_data(self, address: int = 0, length: int = None) -> Optional[bytes]:
        """
        从内存数据中获取指定地址和长度的数据
        
        Args:
            address (int): 起始地址（相对于加载地址）
            length (int): 数据长度，None表示获取到文件末尾的所有数据
            
        Returns:
            Optional[bytes]: 获取的数据，失败返回None
        """
        try:
            if self.memory_data is None:
                return None
            
            # 计算相对于文件数据的偏移量
            offset = address - self.load_address
            
            # 检查偏移量是否有效
            if offset < 0 or offset >= len(self.memory_data):
                return None
            
            # 如果未指定长度，则获取从偏移量到文件末尾的所有数据
            if length is None:
                return self.memory_data[offset:]
            
            # 检查长度是否有效
            if offset + length > len(self.memory_data):
                # 如果请求的长度超出范围，则只返回可用的数据
                length = len(self.memory_data) - offset
            
            return self.memory_data[offset:offset + length]
            
        except Exception:
            return None
    
    def get_file_info(self) -> Dict:
        """
        获取文件信息
        
        Returns:
            Dict: 文件信息字典
        """
        return {
            'file_path': self.file_path,
            'file_size': self.file_size,
            'load_address': self.load_address,
            'memory_size': len(self.memory_data) if self.memory_data else 0
        }
    
    def get_memory_info(self) -> Dict:
        """
        获取内存信息
        
        Returns:
            Dict: 内存信息
        """
        if self.memory_data is None:
            return {}
        
        return {
            'load_address': self.load_address,
            'end_address': self.load_address + len(self.memory_data),
            'memory_size': len(self.memory_data)
        }
    
    def export_to_hex(self, output_path: str, base_address: int = 0) -> bool:
        """
        将BIN数据导出为HEX文件（Intel HEX格式）
        
        Args:
            output_path (str): 输出文件路径
            base_address (int): 基础地址
            
        Returns:
            bool: 导出成功返回True，否则返回False
        """
        try:
            if self.memory_data is None:
                raise ValueError("没有加载的BIN数据")
            
            with open(output_path, 'w') as f:
                address = base_address
                data = self.memory_data
                
                # 分块处理数据（每行最多16字节）
                for i in range(0, len(data), 16):
                    chunk = data[i:i+16]
                    record_type = 0  # 数据记录
                    
                    # 构建记录行
                    line = ":"
                    line += f"{len(chunk):02X}"  # 数据长度
                    line += f"{(address + i) & 0xFFFF:04X}"  # 地址（低16位）
                    line += f"{record_type:02X}"  # 记录类型
                    
                    # 数据字节
                    for byte in chunk:
                        line += f"{byte:02X}"
                    
                    # 计算校验和
                    checksum = 0
                    for j in range(1, len(line), 2):
                        checksum += int(line[j:j+2], 16)
                    checksum = (~checksum + 1) & 0xFF  # 二进制补码
                    line += f"{checksum:02X}"
                    
                    f.write(line + "\n")
                
                # 写入结束记录
                f.write(":00000001FF\n")
            
            return True
        except Exception as e:
            print(f"导出HEX文件失败: {str(e)}")
            return False


class BinFirmwareUpdater:
    """BIN固件升级器类"""
    
    def __init__(self, bin_loader: BinLoader):
        """
        初始化BIN固件升级器
        
        Args:
            bin_loader (BinLoader): BIN加载器实例
        """
        self.bin_loader = bin_loader
        self.upgrade_steps = []  # 升级步骤
        self.current_step = 0    # 当前步骤
        self.is_upgrading = False  # 是否正在升级
        
    def prepare_upgrade(self) -> bool:
        """
        准备升级流程
        
        Returns:
            bool: 准备成功返回True，否则返回False
        """
        try:
            if self.bin_loader.memory_data is None:
                raise ValueError("没有加载的BIN数据")
            
            # 清空之前的升级步骤
            self.upgrade_steps = []
            self.current_step = 0
            
            # 添加默认升级步骤
            self._add_default_upgrade_steps()
            
            return True
        except Exception as e:
            print(f"准备升级失败: {str(e)}")
            return False
    
    def _add_default_upgrade_steps(self):
        """添加默认升级步骤"""
        self.upgrade_steps = [
            "连接设备",
            "擦除Flash",
            "写入固件数据",
            "验证固件数据",
            "重启设备"
        ]
    
    def add_upgrade_step(self, step: str):
        """
        添加自定义升级步骤
        
        Args:
            step (str): 升级步骤描述
        """
        self.upgrade_steps.append(step)
    
    def get_upgrade_steps(self) -> List[str]:
        """
        获取所有升级步骤
        
        Returns:
            List[str]: 升级步骤列表
        """
        return self.upgrade_steps.copy()
    
    def start_upgrade(self) -> bool:
        """
        开始升级流程
        
        Returns:
            bool: 升级开始成功返回True，否则返回False
        """
        try:
            if not self.upgrade_steps:
                raise ValueError("没有定义升级步骤")
            
            self.is_upgrading = True
            self.current_step = 0
            return True
        except Exception as e:
            print(f"开始升级失败: {str(e)}")
            return False
    
    def next_step(self) -> Tuple[bool, Optional[str]]:
        """
        执行下一步升级
        
        Returns:
            Tuple[bool, Optional[str]]: (是否还有下一步, 当前步骤描述)
        """
        if not self.is_upgrading:
            return (False, None)
        
        if self.current_step >= len(self.upgrade_steps):
            self.is_upgrading = False
            return (False, None)
        
        current_step_desc = self.upgrade_steps[self.current_step]
        self.current_step += 1
        
        # 检查是否还有下一步
        has_next = self.current_step < len(self.upgrade_steps)
        
        return (has_next, current_step_desc)
    
    def get_progress(self) -> Tuple[int, int]:
        """
        获取升级进度
        
        Returns:
            Tuple[int, int]: (当前步骤, 总步骤数)
        """
        return (self.current_step, len(self.upgrade_steps))
    
    def cancel_upgrade(self):
        """取消升级"""
        self.is_upgrading = False
        self.current_step = 0


# 使用示例和测试函数
def main():
    """主函数，用于测试和演示"""
    print("BIN加载器和升级流程演示")
    
    # 创建BIN加载器实例
    loader = BinLoader()
    
    # 加载测试BIN文件
    if loader.load_bin_file("test.bin"):
        print("BIN文件加载成功")
        
        # 显示文件信息
        info = loader.get_file_info()
        print(f"文件路径: {info['file_path']}")
        print(f"文件大小: {info['file_size']} 字节")
        print(f"加载地址: 0x{info['load_address']:08X}")
        print(f"内存大小: {info['memory_size']} 字节")
        
        # 显示内存信息
        mem_info = loader.get_memory_info()
        print(f"加载地址: 0x{mem_info['load_address']:08X}")
        print(f"结束地址: 0x{mem_info['end_address']:08X}")
        print(f"内存大小: {mem_info['memory_size']} 字节")
        
        # 读取前16字节数据
        data = loader.get_memory_data(0, 16)
        if data:
            print(f"前16字节数据: {data.hex().upper()}")
        
        # 导出为HEX文件
        if loader.export_to_hex("exported.hex", 0x08000000):
            print("✓ 导出为HEX文件成功")
        else:
            print("✗ 导出为HEX文件失败")
        
        # 创建升级器实例
        updater = BinFirmwareUpdater(loader)
        
        # 准备升级
        if updater.prepare_upgrade():
            print("\n升级准备完成")
            
            # 显示升级步骤
            steps = updater.get_upgrade_steps()
            print("升级步骤:")
            for i, step in enumerate(steps, 1):
                print(f"  {i}. {step}")
            
            # 模拟升级过程
            print("\n开始升级...")
            if updater.start_upgrade():
                while True:
                    has_next, step_desc = updater.next_step()
                    if step_desc:
                        progress = updater.get_progress()
                        print(f"执行步骤: {step_desc} ({progress[0]}/{progress[1]})")
                    
                    if not has_next:
                        break
                
                print("升级完成!")
            else:
                print("升级启动失败")
        else:
            print("升级准备失败")
    else:
        print("BIN文件加载失败")


if __name__ == "__main__":
    main()
